package me.zhengjie.minbearwcs.serivce.agv.task.agvTask.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDetailDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionDetailHistoryDao;
import me.zhengjie.minbearwcs.dao.agv.inf.AgvMissionHistoryDao;
import me.zhengjie.minbearwcs.dao.storage.inf.LargeStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.MediumStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.agv.TUSK.TUSKContentPool;
import me.zhengjie.minbearwcs.entity.DTO.agv.TUSK.TUSKMission;
import me.zhengjie.minbearwcs.entity.DTO.agv.TUSK.TUSKResponse;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.AgvActionSource;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.AgvTaskSource;
import me.zhengjie.minbearwcs.entity.DTO.agv.task.actionEnum.AgvAction;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvContentPool;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMission;
import me.zhengjie.minbearwcs.entity.PO.agv.AgvMissionDetail;
import me.zhengjie.minbearwcs.entity.PO.agv.history.AgvMissionDetailHistory;
import me.zhengjie.minbearwcs.entity.PO.agv.history.AgvMissionHistory;
import me.zhengjie.minbearwcs.entity.PO.agv.missionEnum.AgvMissionStatus;
import me.zhengjie.minbearwcs.entity.PO.wcs.outbound.stockUp.PalletMediumStorageSearchPo;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.LargeStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.MediumStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.type.StorageType;
import me.zhengjie.minbearwcs.serivce.agv.task.agvTask.AgvTaskDispatcher;
import me.zhengjie.minbearwcs.utils.IdWorker;
import me.zhengjie.minbearwcs.utils.WcsHpptUtil;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class AgvTaskDispatcherImpl implements AgvTaskDispatcher {

    private final IdWorker idWorker;
    private final AgvMissionDao agvMissionDao;
    private final AgvMissionDetailDao agvMissionDetailDao;
    private final WcsHpptUtil wcsHpptUtil;
    private final AgvMissionDetailHistoryDao agvMissionDetailHistoryDao;
    private final AgvMissionHistoryDao agvMissionHistoryDao;
    private final SmallStorageDao smallStorageDao;
    private final MediumStorageDao mediumStorageDao;
    private final LargeStorageDao largeStorageDao;
    private final StorageDao storageDao;
//    private final TestController agvDispatcher;

    @Override
    public boolean dispatch(AgvTaskSource agvTaskSource) {
        MDC.put("moduleName", "Agv");

        String taskId = "Task_Agv_" + idWorker.nextId();
        String targetCollect = agvTaskSource.getActionList()
                .stream()
                .map(AgvActionSource::getPoint)
                .collect(Collectors.joining(",", "[", "]"));

        AgvMission agvMission = new AgvMission(null, taskId, agvTaskSource.getMissionType(), AgvMissionStatus.READY,
                1, targetCollect, agvTaskSource.getActionList().size(), AgvContentPool.AGV_ACTION_INIT, null, agvTaskSource.getPalletCode(), agvTaskSource.getWcsMissionId(),
                agvTaskSource.getWcsMissionType(), agvTaskSource.getWcsMissionStatus(), LocalDateTime.now(),
                null, null);
        agvMissionDao.insert(agvMission);

        AtomicInteger actionIndexCount = new AtomicInteger(1);
        agvTaskSource.getActionList()
                .stream()
                .map(a -> new AgvMissionDetail(null, taskId, actionIndexCount.getAndIncrement(), a.getPoint(),
                        a.getAction().name(), null, 0))
                .collect(Collectors.toList())
                .forEach(agvMissionDetailDao::insert);

        List<String> pointList = agvTaskSource.getActionList()
                .stream()
                .map(AgvActionSource::getPoint)
                .collect(Collectors.toList());

        TUSKMission tuskMission = new TUSKMission(taskId, pointList, agvTaskSource.getMissionType().getTuskType(),
                agvTaskSource.getStartPass(), agvTaskSource.getEndPass());
        TUSKResponse tuskResponse = wcsHpptUtil.dispatchTUSKMission(tuskMission);

//        Result<Object> objectResult = agvDispatcher.sentTask(
//                agvTaskSource.getActionList().get(0).getPoint(),
//                agvTaskSource.getActionList().get(1).getPoint(),
//                taskId,
//                agvTaskSource.getMissionType().getTuskType()
//        );

        MDC.remove("moduleName");

        return Objects.equals(tuskResponse.getCode(), TUSKContentPool.TUSK_SUCCESS_CODE);
    }


    @Override
    @Transactional
    public boolean cancel(String taskId) {
        MDC.put("moduleName", "Agv");

        AgvMission agvMission = agvMissionDao.selectByTaskId(taskId);
        if (agvMission == null) {
            log.info("AGV任务：{}，不存在，取消失败", taskId);
            return false;
        }

        if (AgvMissionStatus.READY != agvMission.getTaskStatus()) {
            log.info("AGV任务：{}，已开启，取消失败", taskId);
            return false;
        }


        TUSKResponse tuskResponse = wcsHpptUtil.cancelTUSKMission(taskId);
        if (!Objects.equals(tuskResponse.getCode(), TUSKContentPool.TUSK_SUCCESS_CODE)) {
            log.info("AGV任务：{}，TUSK取消失败", taskId);
            return false;
        }


        //2.更新agv任务

        // 3.把agv任务转移到历史任务表
        List<AgvMissionDetail> agvMissionDetails = agvMissionDetailDao.selectByTaskId(taskId);
        for (AgvMissionDetail missionDetail : agvMissionDetails) {
            AgvMissionDetailHistory agvMissionDetailHistory = new AgvMissionDetailHistory(null, missionDetail.getTaskId(), missionDetail.getTaskIndex(),
                    missionDetail.getPoint(), missionDetail.getAction(), missionDetail.getMarkTime(),
                    missionDetail.getIsComplete());
            agvMissionDetailHistoryDao.insert(agvMissionDetailHistory);
            agvMissionDetailDao.deleteById(missionDetail.getId());
        }

        AgvMissionHistory agvMissionHistory = new AgvMissionHistory(null, agvMission.getTaskId(), agvMission.getMissionType(), AgvMissionStatus.CANCEL,
                agvMission.getPriority(), agvMission.getTargetCollection(), agvMission.getTotalActionNum(), agvMission.getCompleteActionNum(),
                agvMission.getAgvId(), agvMission.getPalletCode(), agvMission.getWcsMissionId(), agvMission.getWcsMissionType(),
                agvMission.getWcsMissionStatus(), agvMission.getCreateTime(), agvMission.getStartTime(), LocalDateTime.now());
        agvMissionHistoryDao.insert(agvMissionHistory);
        agvMissionDao.deleteById(agvMission.getId());


        // 清空起点储位
        AgvMissionDetail agvMissionGet = agvMissionDetails.stream()
                .filter(a -> AgvAction.GET.name().equals(a.getAction()))
                .findAny()
                .get();
        smallStorageDao.clearOutboundFreeze(agvMissionGet.getPoint());

        // 清空终点储位
        AgvMissionDetail agvMissionPut = agvMissionDetails.stream()
                .filter(a -> AgvAction.PUT.name().equals(a.getAction()))
                .findAny()
                .get();
        smallStorageDao.clearStoragePallet(agvMissionPut.getPoint());
        judgeAndClearMediumStorage(agvMissionPut.getPoint());


        MDC.remove("moduleName");
        return true;
    }


    // 清除小储位后，清理中储位物料信息
    private void judgeAndClearMediumStorage(String smallStorageCode) {
        SmallStorage smallStorage = smallStorageDao.selectBySmallStorage(smallStorageCode);
        MediumStorage mediumStorage = mediumStorageDao.selectByMediumStorage(smallStorage.getMediumStorageCode());
        LargeStorage largeStorage = largeStorageDao.selectByLargeStorageCode(mediumStorage.getLargeStorageCode());

        if (StorageType.STORAGE_AREA_5F != largeStorage.getLargeStorageType() &&
                StorageType.STORAGE_AREA_6F != largeStorage.getLargeStorageType()) return;

        List<PalletMediumStorageSearchPo> palletMediumStorageSearchPoList = storageDao.selectPalletOrOutboundFreezePalletMediumStorage(smallStorage.getMediumStorageCode());

        Map<String, Long> collect = palletMediumStorageSearchPoList.stream()
                .map(a -> a.getMaterialCode() + a.getInboundOrderCode() + a.getBatchCode())
                .collect(Collectors.groupingBy(a -> a, Collectors.counting()));


        String mediumMaterial1 = mediumStorage.getMaterialOne() + mediumStorage.getInboundOrderOne() + mediumStorage.getBatchOne();
        String mediumMaterial2 = mediumStorage.getMaterialTwo() + mediumStorage.getInboundOrderTwo() + mediumStorage.getBatchTwo();

        Long num1 = collect.getOrDefault(mediumMaterial1, 0l);
        Long num2 = collect.getOrDefault(mediumMaterial2, 0l);

        if (num1 == 0l) {
            mediumStorageDao.updateBatch1Info(smallStorage.getMediumStorageCode(), null, null, null);
        }

        if (num2 == 0l) {
            mediumStorageDao.updateBatch2Info(smallStorage.getMediumStorageCode(), null, null, null);
        }
    }

}
